package com.agenda.client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.JOptionPane;
import com.agenda.PrincipalCliente;
import com.agenda.client.listeners.RecebimentoClienteListener;
import com.agenda.client.requisicoes.SolicitarVideoRequisicao;
import com.agenda.client.view.ChatView;
import com.agenda.model.RespostaRequisicao;
import com.agenda.model.Sala;
import com.agenda.model.Usuario;
import com.agenda.model.UsuarioIP;
import com.agenda.util.FileUtil;
import com.agenda.video.Conferencia;

public class SalaChatLadoCliente implements RecebimentoClienteListener {

	private static int COUNT = 1;

	private ArrayList<UsuarioIP> usuariosIP = new ArrayList<UsuarioIP>();

	private Sala sala = new Sala();

	private UsuarioIP root;
	private Socket sckRoot;

	private Boolean iniciouSala = false;

	private ArrayList<Usuario> confirmados = new ArrayList<Usuario>();

	private ChatView chatView = new ChatView();

	public SalaChatLadoCliente() {
		sala.setNumero(COUNT);

		COUNT++;

		chatView.setSalaCliente(this);
	}

	public ArrayList<UsuarioIP> getUsuariosIP() {
		return usuariosIP;
	}

	public void setUsuariosIP(ArrayList<UsuarioIP> usuariosIP) {
		this.usuariosIP = usuariosIP;
	}

	public void enviarRequisicoes() {

		String meuIp = ClienteServidor.getINSTANCIA().getSocket().getInetAddress().getHostAddress();
		UsuarioIP meuUsaurioIp = new UsuarioIP();
		meuUsaurioIp.setIp(meuIp);
		meuUsaurioIp.setUsuario(PrincipalCliente.getUsuarioLogado());
		for (UsuarioIP usuarioIP : usuariosIP) {
			try {
				Socket socket = RequisicaoAoClienteThread.sckClientes.get(usuarioIP.getUsuario());

				if (socket == null) {
					socket = new Socket(usuarioIP.getIp(), ClienteServidor.PORTA_RECEBIMENTO);
					RequisicaoAoClienteThread.sckClientes.put(usuarioIP.getUsuario(), socket);
				}

				OutputStream output = socket.getOutputStream();
				output.write(RequisicaoAoClienteThread.SOLICITACAO_CHAT);

				ObjectOutputStream objOutPut = new ObjectOutputStream(socket.getOutputStream());
				objOutPut.writeObject(sala);
				objOutPut.writeObject(meuUsaurioIp);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		chatView.ativarBotaoVideo();
	}

	public void setRoot(UsuarioIP userIp) {
		this.root = userIp;
	}

	public void setSala(Sala sala) {
		this.sala = sala;
	}

	@Override
	public void receber(int requisiciao, ConcurrentHashMap<String, Object> valores) {
		System.out.println("REQUISICAO  +++ " + requisiciao);
		if (requisiciao == RequisicaoAoClienteThread.RESPOSTA_SOLICITACAO_CHAT) {
			Sala sala = (Sala) valores.get("sala");
			if (sala.getNumero() == this.sala.getNumero()) {
				Boolean resposta = (Boolean) valores.get("resposta");
				if (resposta) {
					Usuario usuario = (Usuario) valores.get("usuario");
					adicionarUsuarioConfirmado(usuario);

					System.out.println("SOLICITACAO 01");

					if (!iniciouSala) {
						System.out.println("SOLICITACAO 02");
						iniciouSala = true;
						abrirTelaChat();
					}

					System.out.println("SOLICITACAO 03");
					abrirTelaChatRemota(usuario);
				}
			}
		}

		if (requisiciao == RequisicaoAoClienteThread.MENSAGEM_CHAT) {
			Sala sala = (Sala) valores.get("sala");
			if (sala.getNumero() == this.sala.getNumero()) {
				Usuario usuario = (Usuario) valores.get("usuario");
				String mensagem = (String) valores.get("mensagem");

				if (root == null) {
					try {
						enviarMensagemRoot(usuario, mensagem);
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else {
					chatView.addMensagem(usuario, mensagem);
				}
			}
		}

		if (requisiciao == RequisicaoAoClienteThread.ABRIR_TELA_CHAT) {
			Sala sala = (Sala) valores.get("sala");
			if (sala.getNumero() == this.sala.getNumero()) {
				abrirTelaChat();
			}
		}

		if (requisiciao == RequisicaoAoClienteThread.INICIAR_VIDEO) {
			Sala sala = (Sala) valores.get("sala");
			if (sala.getNumero() == this.sala.getNumero()) {
				iniciarVideo((Usuario) valores.get("usuario"));
			}
		}

		if (requisiciao == RequisicaoAoClienteThread.ENVIAR_ARQUIVO) {
			Sala sala = (Sala) valores.get("sala");
			if (sala.getNumero() == this.sala.getNumero()) {
				Usuario usuario = (Usuario) valores.get("usuario");
				String nomeArquivo = (String) valores.get("nomeArquivo");
				try {
					if (root == null)
						enviarArquivoTodosClientes(new File(nomeArquivo), usuario);
				} catch (Exception e) {
					e.printStackTrace();
					JOptionPane.showMessageDialog(chatView, e.getMessage());
				}
				JOptionPane.showMessageDialog(chatView, "Você recebeu o '" + nomeArquivo + "' de '" + usuario + "'.");
			}
		}
	}

	private void iniciarVideo(Usuario usuario) {
		Socket sckSocket = RequisicaoAoClienteThread.sckClientes.get(usuario);
		if (root != null)
			sckSocket = sckRoot;

		iniciarVideo(sckSocket);
	}

	private void iniciarVideo(Socket sckSocket) {
		if (sckSocket != null)
			Conferencia.iniciarConferencia(sckSocket.getLocalAddress().getHostAddress(), sckSocket.getInetAddress().getHostAddress());
	}

	public void enviarMensagemRoot(Usuario usuario, String mensagem) throws Exception {
		if (root == null) {
			//No caso do root ele não envia para ele mesmo... +)
			chatView.addMensagem(usuario, mensagem);

			for (Usuario usuarioConfirmado : confirmados) {
				enviarMensagemCliente(RequisicaoAoClienteThread.sckClientes.get(usuarioConfirmado), usuario, mensagem);
			}
		} else {
			enviarMensagemCliente(sckRoot, usuario, mensagem);
		}
	}

	private void enviarMensagemCliente(Socket sck, Usuario usuario, String mensagem) throws Exception {
		OutputStream output = sck.getOutputStream();
		output.write(RequisicaoAoClienteThread.MENSAGEM_CHAT);

		ObjectOutputStream objOutPut = new ObjectOutputStream(output);

		objOutPut.writeObject(sala);
		objOutPut.writeObject(usuario);
		objOutPut.writeObject(mensagem);
	}

	private void abrirTelaChatRemota(Usuario usuario) {
		try {
			Socket socket = RequisicaoAoClienteThread.sckClientes.get(usuario);

			OutputStream output = socket.getOutputStream();
			output.write(RequisicaoAoClienteThread.ABRIR_TELA_CHAT);

			ObjectOutputStream objOutPut = new ObjectOutputStream(output);
			objOutPut.writeObject(sala);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void abrirTelaChat() {

		chatView.setLocationRelativeTo(null);
		chatView.setVisible(true);
	}

	private void adicionarUsuarioConfirmado(Usuario usuario) {
		confirmados.add(usuario);
	}

	public void confirmarRecusarSolicitacao(boolean confirmou) {

		try {
			sckRoot = new Socket(root.getIp(), ClienteServidor.PORTA_RECEBIMENTO);

			OutputStream output = sckRoot.getOutputStream();
			output.write(RequisicaoAoClienteThread.RESPOSTA_SOLICITACAO_CHAT);

			ObjectOutputStream objOutPut = new ObjectOutputStream(output);
			objOutPut.writeObject(sala);
			objOutPut.writeObject(PrincipalCliente.getUsuarioLogado());
			objOutPut.writeObject(new Boolean(confirmou));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void iniciarVideo() throws Exception {
		Boolean videoLiberado = Boolean.FALSE;
		try {
			RespostaRequisicao resposta = ClienteServidor.getINSTANCIA().enviarInformacao(new SolicitarVideoRequisicao(sala));
			if (resposta.isErro())
				JOptionPane.showMessageDialog(chatView, resposta.getMsg());

			videoLiberado = (Boolean) ClienteServidor.getINSTANCIA().lerObjeto();
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(chatView, e.getMessage());
		}
		ClienteServidor.getINSTANCIA().liberarComunicacao();

		if (videoLiberado) {
			Socket sck = null;
			if (root != null)
				sck = sckRoot;
			else {
				sck = RequisicaoAoClienteThread.sckClientes.get(confirmados.get(0));
			}

			OutputStream output = sck.getOutputStream();
			output.write(RequisicaoAoClienteThread.INICIAR_VIDEO);

			ObjectOutputStream objOutPut = new ObjectOutputStream(output);
			objOutPut.writeObject(sala);
			objOutPut.writeObject(PrincipalCliente.getUsuarioLogado());

			Conferencia.iniciarConferencia(sck.getLocalAddress().getHostAddress(), sck.getInetAddress().getHostAddress());
		} else {
			JOptionPane.showMessageDialog(chatView, "Video não pode ser liberado.");
		}
	}

	public void enviarArquivo(File file) throws Exception {
		if (root == null) {
			enviarArquivoTodosClientes(file, null);
		} else {
			enviarArquivoParaOServidor(file);
		}
	}

	private void enviarArquivoParaOServidor(File file) throws Exception {
		enviarArquivoSocket(file, sckRoot);
	}

	private void enviarArquivoSocket(File file, Socket sck) throws Exception {

		OutputStream output = sck.getOutputStream();
		output.write(RequisicaoAoClienteThread.ENVIAR_ARQUIVO);

		ObjectOutputStream objOutPut = new ObjectOutputStream(output);
		objOutPut.writeObject(sala);
		objOutPut.writeObject(PrincipalCliente.getUsuarioLogado());
		objOutPut.writeObject(file.getName());

		BufferedInputStream fileInputStream = new BufferedInputStream(new FileInputStream(file));
		BufferedOutputStream bufferOutput = new BufferedOutputStream(output, 1024);

		FileUtil.enviar(bufferOutput, fileInputStream, sck.getInputStream());

		fileInputStream.close();

		int confirmou = sck.getInputStream().read();
		if (confirmou == 1) {
			System.out.println("Confirmou recebimento do arquivo.");
		}
	}

	private void enviarArquivoTodosClientes(File file, Usuario usuarioAExcluir) throws Exception {
		for (Usuario userConfirmado : confirmados) {
			if (!userConfirmado.equals(usuarioAExcluir)) {
				Socket sckUser = RequisicaoAoClienteThread.sckClientes.get(userConfirmado);
				enviarArquivoSocket(file, sckUser);
			}
		}
	}

}
